package nl.scalasim.cli

import util.parsing.combinator.syntactical.StandardTokenParsers

/**
 * Parser for the CLI interface
 *
 * @author Yigal Duppen
 * @since Sep 30, 2010
 */
class CLIParser extends StandardTokenParsers {

  val commands = Set("quit", "map", "status", "list", "go", "describe", "build", "raze", "route")

  lexical.delimiters += ("?", ",")
  lexical.reserved ++= commands + ("at", "to")

  def cmd: Parser[Command] = (
          "?" ^^ {case _ => Help}
                  | "quit" ^^ {case _ => Quit}
                  | "map" ^^ {case _ => ShowMap}
                  | "status" ^^ {case _ => Status}
                  | "list" ^^ {case _ => List}
                  | "go" ~ opt(numericLit)
                  ^^ {
            case _ ~ Some(x) => Go(x.toInt)
            case _ ~ None => Go(1)
          }
                  | "describe" ~ numericLit ~ "," ~ numericLit
                  ^^ {case _ ~ x ~ _ ~ y => Describe((x.toInt, y.toInt))}
                  | "build" ~ stringLit ~ "at" ~ numericLit ~ "," ~ numericLit
                  ^^ {case _ ~ n ~ _ ~ x ~ _ ~ y => Build(n, (x.toInt, y.toInt))}
                  | "raze" ~ numericLit ~ "," ~ numericLit
                  ^^ {case _ ~ x ~ _ ~ y => Raze((x.toInt, y.toInt))}
                  | "route" ~ numericLit ~ "," ~ numericLit ~ "to" ~ numericLit ~ "," ~ numericLit
                  ^^ {case _ ~ x ~ _ ~ y ~ _ ~ x2 ~ _ ~ y2 => DebugRoute((x.toInt, y.toInt), ((x2.toInt, y2.toInt)))}
          )


  def parse(command: String): Command = {
    val tokens = new lexical.Scanner(command)
    val result = phrase(cmd)(tokens)

    if (result.successful) {
      result.get
    }
    else {
      (commands + "?") find {s => command.startsWith(s)} match {
        case None => UnknownCommand
        case Some(prefix) => MalformedCommand(prefix)
      }
    }
  }

}